package partFour;
/*设计多线程编程模型，4个窗口购机售票100张
 * 本方案使用多线程编程方案1，继承Thread类的方式来完成*/
public class TestThreatv2 {
    public static void main(String[] args) {
        //5.创建多个线程对象
        TicketsThread2 t1 = new TicketsThread2();
        TicketsThread2 t2= new TicketsThread2();
        TicketsThread2 t3 = new TicketsThread2();
        TicketsThread2 t4 = new TicketsThread2();
        //6.以多线程的方式启动
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}
/* 1.多线程中出现数据安全问题的原因：多线程程序+有共享数据+多条语句可操作共享数据*/
/* 2.同步锁：相当于给容易出现问题的代码加了一把锁，加锁以后，这些代码实现同步效果
 * 同步就是排队，需要考虑俩个问题：
 * 1）加锁的范围：不能太大，太大，效率太低，不能太小，太小，锁不住
 * 2）多个线程对象必须是同一把锁，锁对象只有一个，不然锁不住*/
//1.自定义多线程售票类，继承Thread
class TicketsThread2 extends Thread{
    //3.定义变量，保存要卖的票数,需要设置静态，不然4个线程对象每个线程对象都会有100张票
    //4个线程对象每个线程对象售票400张，原因是创建了4次对象，各自操作各自的成员变量
    // 解决：让所有对象共享同一个数据，票数需要设置为静态
    static int tickets = 100;
    /* 创建锁对象，锁对象的类型不做限制，但是得唯一*/
    //Object o = new Object();  //如果是继承，锁对象不要自定义
    //2.重新run方法
    @Override
    public void run(){
        //4.1循环卖票，使用while循环，方便后续演示容易出错的位置
        while (true) {
            /*当前类的字节码对象，这个是肯定唯一的*/
            synchronized (TicketsThread2.class) {
                if(tickets>0){//双重校验，解决超卖
                    //4.2打印当前正在卖票的线程名称，并且票数-1
                    System.out.println(getName() + "=" + tickets--);
                    //4.3做判断，如果没有票了，就退出死循环
                }

                if (tickets <= 0) break;//注意，死循环一定要设置出口
            }
        }
    }
}